[Report][AWS Summit Online ASEAN RE:CAP 2020]Hiện đại hoá Kiến trúc ứng dụng trên AWS
Ngày 29/09/2020 vừa rồi đã diễn ra sự kiện AWS Summit Online ASEAN RE:CAP. Link sự kiện: https://live.awsevents.com/ASEANSummitreCap/
Chủ để của session lần này là "Các mẫu kiến trúc: Xử lý luồng không cần máy chủ ở quy mô" Diễn giả: Hoàng Minh Chính, Solutions Architect, Amazon Web Services
Ngày nay, khách hàng thường gặp nhiều khó khăn trong việc xây dựng các ứng dụng mang tính sẵn sàng cao, cũng như có khả năng mở rộng tốt. Điều này đúng cả với trường hợp xây dựng ứng dụng mới, hoặc trường hợp hiện đại hoá ứng dụng cũ theo hướng tối ưu cho môi trường điện toán đám mây.
Trong webinar này, chúng tôi sẽ cùng các bạn đi sâu vào một số kiến trúc ứng dụng hiện đại và best practice trên AWS, cách các nhóm DevOps tận dụng hạ tầng điện toán đám mây AWS để giảm thời gian xây dựng ứng dụng, trong khi vẫn đảm bảo khả năng quản lý hạ tầng.
1. Điều khách hàng muốn
Dựa trên phải hồi từ khách hàng:
- Thứ nhất, khách hàng không muốn quản lý hạ tầng, mà chỉ muốn tập trung thời gian vào việc phát triển ứng dụng, nơi mang lại giá trị thực sự thay vì dành thời gian để xử lý sự cố hay quản lý hạ tầng
- Thứ hai, khách hàng muốn tập trung vào chất lượng ứng dụng, mở rộng khi cần thiết, co lại khi tải ít, và để chúng tôi đảm nhận công việc quản lý hạ tầng.
- Thứ ba, khách hàng không muốn mất thời gian để tìm hiểu cách triển khai ứng dụng lên hạ tầng vật lý
- Thứ tư, đảm bảo an toàn bảo mật
2. Những lựa chọn khi xây dựng ứng dụng trên cloud
- Các ứng dụng truyền thống: thường được xây dựng thành các lớp liên kết chặt chẽ, và thường được đóng gói thành một khối, điều này gây khó khăn trong việc nâng cấp, sửa lỗi và vận hành.
- Các ứng dụng hiện đại: (Microservices) Thay vì xây dựng ứng dụng thành các khối lớn, ứng dụng được chia nhỏ thành rất nhiều bộ phận hoạt động độc lập và phân tán.
Một kiến trúc thường gặp với ứng dụng Microservices là ứng dụng dựa trên sự kiện. Trong ứng dụng này, các thành phần của kiến trúc liên lạc với nhau thông qua API dựa trên các sự kiện.
Trên AWS, để xây dựng ứng dụng microservices, chúng ta có một số lựa chọn:
- Nếu sử dụng theo hướng container, chúng ta có thể sử dụng Amazon ECS, Amazon EKS, AWS Fargate
- Nếu sử đụng theo hướng serverless, chúng ta có thể sử dụng AWS Lambda
Vậy Serverless là gì?
Nói một cách ngắn gọn, với các dịch vụ serverless, AWS sẽ đảm nhận việc quản lý hạ tầng, khởi tạo máy chủ, network, hệ thống lưu trữ. Khách hàng không cần quan tâm tới việc này. AWS cũng đảm bảo hạ tầng bảo mật và tự động co dãn theo yêu cầu của ứng dụng. Trong mô hình serverless, khách hàng chỉ trả chi phí cho đúng nhu cầu sử dụng tài nguyên vào đúng khoảng thời gian sử dụng. Đây là điểm hấp dẫn của các dịch vụ như Lambda.
Nhìn vào hình dưới, khi chúng ta đi từ dưới lên trên, qua các lựa chọn EC2, AWS ECS/EKS, AWS Fargate, AWS Lambda, trách nhiệm quản lý hạ tầng dần dần chuyển từ khách hàng sang AWS
3. Chúng ta nên lựa chọn thế nào?
- Chúng ta có thể bắt đầu từ kích thước package ứng dụng. nếu package nhỏ, thời gian chạy không quá 15 phút, và không có yêu cầu liên lạc giữa các thành phần container => Lambda sẽ là lựa chọn hợp lý.
- Nếu các container cần liên lạc với nhau, và chúng ta cần khả năng chuyển đổi hạ tầng từ on-premises lên các nên tảng cloud khác nhau, hoặc đơn giản là đội vận hành đã quen thuộc với Kubenetes => Chúng ta có thể dùng Amazon EKS.
- Nếu không chúng ta có thể dùng AWS ECS và dùng Orchestrator của AWS
- Cuối cùng, nếu chúng ta không muốn quản lý cluster máy chủ chạy container => Fargate sẽ là lựa chọn phù hợp
Khi cân nhắc xây dựng mô hình ứng dụng trên AWS, một điểm quan trọng chúng ta cần nhớ là luôn đặt câu hỏi chúng ta có thực sự cần container không? Dựa trên kinh nghiệm của chúng tôi khi làm việc với khách hàng, cách đơn giản nhất để bắt đầu là chúng ta tận dụng tối đa các dịch vụ serverless có sẵn.
4. Best practices khi sử dụng dịch vụ serverless Lambda
AWS Lambda:
- Dịch vụ cho phép khách hàng chạy các đoạn mã nguồn mà không cần triển khai, hay quản lý máy chủ
- Khách hàng chỉ cần trả chi phí cho thời gian và năng lực tính toán sử dụng
- AWS đảm nhận việc quản lý, bảo mật hạ tầng và tự động co dãn theo số lượng yêu cầu
- Một Lambda Function bao gồm nhiều lớp: Lớp hạ tầng tính toán, lớp môi trường thực thi, lớp mã nguồn
Mỗi hàm Lambda bao gồm một số thành phần
- Phần quan trọng nhất là hàm Lambda Handler(). Ở đây chứa mã nguồn được thực thi cho mỗi lầm Lambda được kích hoạt. Hàm Lambda Handler() nhận 2 đối tượng đầu vào Event và Context
- Đối tượng Event chưa dữ liệu truyền vào cho Lambda
- Đối tượng Context chứa dữ liệu về môi trường thực thi và Runtime. VD: Tên function, giới hạn bộ nhớ
- Mã nguồn nằm trước hàm Lambda được coi là các hàm khởi tạo và chạy cùng với quá trình khởi tạo container. Đây là nơi phù hợp để chạy các lệnh khởi tạo như khởi tạo biến, kết nối tới cơ sở dữ liệu.
- Môi trường thực thi của Lambda được tái sử dụng cho các lần gọi hàm sau. Vì vậy chúng ta cần lưu ý 1 số điểm: Lazy load các biến global, không tải biến nếu chúng ta không cần đến, điều này sẽ ảnh hưởng tới cold start (thời gian cần thiết để khởi tạo môi trường cho lần đầu gọi hàm), dọn dẹp biến sau khi dùng xong
Một ứng dụng Serverless điển hình thường bao gồm các thành phần chính
- API Gateway nhận các yêu cầu từ phía Clients. API điều hướng các yêu cầu tới các hàm Lambda phù hợp phía back-end.
- Lambda Function thực thi và truy cập dữ liệu từ cơ sở dữ liệu. VD: DynamoDB
- Tuỳ vào số lượng yêu cầu từ API Gateway, hệ thống sẽ tự động co dãn, và cung câp đủ năng lực cho môi trường tính toán
- Các thông số đầu vào cho Lambda. VD: Connection Strings, Account truy cập hay các biến môi trường được lưu vào AWS Secrets Manager hoặc Parameter Store
Nếu chúng ta có một số lượng lớn các Lambda Functions, và mỗi Lambda Funtion lại dùng chung 1 đoạn mã nguồn xử lý, chúng ta có thể có rất nhiều đoạn mã nguồn trùng lặp ở các functions khác nhau. Giải pháp là sử dụng Lambda Layer
Do kiến trúc của Lambda là stateless, nên chúng ta cần cân nhắc khi thiết kế
- Ứng dụng cần phát triển để không phụ thuộc vào trạng thái, hay phần cứng hạ tầng
- Do môi trường thực thi của Lambda có thể tái sử dụng, ứng dụng cần giả định môi trường thực thi có thể thay đổi và chuẩn bị để xử lý các tình huống nhu kết nối lại đến cơ sở dữ liệu, hay dọn dẹp các biến sau khi sử dụng xong.
Tổng kết một số Best practices về Lambda:
- Tối thiểu hoá kích thước của package Lambda
- Logic xử lý lõi nên được tách thành hàm riêng ở bên ngoài hàm Lambda Handler()
- Dùng biến môi trường truyền từ bên ngoài vào.
- Đóng gói toàn bộ thư viện phụ thuộc (Dependencies) vào trong package Lambda
- Theo dõi Logs của Lambda trong Cloudwatch và xem hàm Lambda thực hiện dùng bao nhiêu bộ nhớ từ đó hiệu chỉnh kích thước Lambda cho hợp lý
- Tránh sử dụng hàm đệ quy với Lambda
5. Best practices khi sử dụng Container
Khi tối ưu container, chúng ta cần lưu ý một số điểm
- Ưu tiên việc giảm kích thước container
- Nên lựa chọn image có vừa đúng những phần mềm, thư viện, runtime chúng ta cần
- Không phải tất cả runtime đều như nhau
Những based image phổ biến rất khác nhau về kích thước
6. Tối ưu hoá Docker image
- Chúng ta nên dùng Multi-stage Docker build
- Một số điểm cần cân nhắc khi sử dụng Kubenetes: Tối ưu pod nhẹ nhất có thể, cân nhắc số lượng hợp lý sidecar nếu cần, cân nhắc việc sử dụng admission controller
7. Tổng kết các best practices
- Bắt đầu bằng sử dụng các dịch vụ serverless có sẵn
- Chỉ sử dụng container khi cần thiết
- Lambda
- Stateless
- Trong Lambda Functions, những thành phần khởi tạo môi trường nên đặt ra ngoài Lambda Handler()
- Sử dụng Lambda Layer
- Sử dụng RDS Proxy khi kết nối tới RDS ở phía sau
- Containers
- Dùng Multi-stage docker build
- Lựa chọn container image
- Đưa thêm các thông số ràng buộc về mặt tài nguyên
Nếu bạn thấy thú vị và muốn tìm hiểu thêm.. Hay truy cập đường link của sự kiện và tìm video của session "Hiện đại hoá Kiến trúc ứng dụng trên AWS"
Cảm ơn các bạn đã theo dõi blog. Xin chào và hẹn gặp lại!